package be.stijn.gdocs.services;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gdata.client.Query;
import com.google.gdata.client.docs.DocsService;
import com.google.gdata.data.MediaContent;
import com.google.gdata.data.PlainTextConstruct;
import com.google.gdata.data.docs.DocumentEntry;
import com.google.gdata.data.docs.DocumentListEntry;
import com.google.gdata.data.docs.DocumentListFeed;
import com.google.gdata.data.docs.FolderEntry;
import com.google.gdata.data.docs.PdfEntry;
import com.google.gdata.data.docs.PresentationEntry;
import com.google.gdata.data.docs.SpreadsheetEntry;
import com.google.gdata.util.ServiceException;

public class UploadService {

    private final DocsService docService;
    private final Logger logger = LoggerFactory.getLogger(UploadService.class);
    private static final String UPLOAD_URL = "https://docs.google.com/feeds/default/private/full/";

    public UploadService(DocsService docService) {
        this.docService = docService;
    }

    /**
     * 
     * @param file
     *            The file who needs to be uploaded.
     * @param root
     *            The root directory of the file,
     *            (example when d:/documents is the root of the file d:/documents/dir1/file.doc then the file will be
     *            placed in /dir1/file.doc on google docs.)
     * @throws IOException
     * @throws ServiceException
     */
    public void upload(SyncFile file) throws IOException, ServiceException {
        String fileName = file.getName().substring(0, file.getName().lastIndexOf('.'));
        String mimeType = DocumentListEntry.MediaType.fromFileName(file.getName()).getMimeType();

        logger.trace(String.format("Uploading %s as %s ...", fileName, mimeType));

        DocumentListEntry newDocument = new DocumentListEntry();
        newDocument.setFile(file.getFile(), mimeType);
        newDocument.setTitle(new PlainTextConstruct(fileName));

        DocumentListEntry entry = docService.insert(new URL(UPLOAD_URL), newDocument);
        logger.trace("...upload complete!");

        if (!file.isAtRoot()) {
            DocumentListEntry documentFolder = createFolders(file);

            logger.trace(String.format("Moving file to folder %s...", documentFolder.getTitle().getPlainText()));

            moveToFolder(entry, documentFolder);
        }
    }

    private DocumentListEntry createFolders(SyncFile file) throws IOException, ServiceException {
        // Don't create folder if folder with equal parent folders already exists.
        DocumentListEntry folder = getFolder(file);
        if (folder != null) {
            return folder;
        }

        File parent = file.getLocalDirectory();
        DocumentListEntry childFolder = null;
        DocumentListEntry documentFolder = null;
        while (!parent.equals(file.getRootDirectory())) {
            DocumentListEntry parentFolder = createFolder(parent.getName());
            if (childFolder != null) {
                moveToFolder(childFolder, parentFolder);
            }
            else {
                documentFolder = parentFolder; // The first folder has no parent but is the folder where we want to
                                               // place to document in.
            }
            childFolder = parentFolder;
            parent = parent.getParentFile();
        }
        return documentFolder;
    }

    /**
     * Retrieves the folder on google docs, with it's parent folder taken into account.
     * 
     * @param file
     * @param root
     *            The root directory on the local file system.
     * @return The DocumentListEntry on google docs when a equal folder with equal parent folders has been found,
     *         returns null when otherwise.
     */
    private DocumentListEntry getFolder(SyncFile file) {
        try {
            URL url = new URL("https://docs.google.com/feeds/default/private/full/-/folder");
            Query qry = new Query(url);
            qry.setStringCustomParameter("showfolders", "true");

            List<String> parents = file.getParentFolderList();

            qry.setStringCustomParameter("q", parents.get(0));
            DocumentListFeed feed = docService.query(qry, DocumentListFeed.class);
            // TODO return when this is the highest folder
            for (DocumentListEntry folder : feed.getEntries()) {

                URL urlc = new URL(String.format(
                        "https://docs.google.com/feeds/default/private/full/folder%%3A%s/contents/-/folder",
                        folder.getDocId()));
                Query qryc = new Query(urlc);
                DocumentListFeed feedc = docService.query(qryc, DocumentListFeed.class);

                for (DocumentListEntry subfolder : feedc.getEntries()) {
                    // loops trough all the subfolders
                    if (subfolder.getTitle().getPlainText().equals(parents.get(1))) {
                        // TODO
                    }
                }

            }

            return null;
        }
        catch (Exception e) {
            logger.error("Exception: ", e);
            return null; // Assume that the folder doesn't exists on google docs.
        }
    }

    private DocumentListEntry getSubFolder(SyncFile file, String parentDocId) throws IOException, ServiceException {
        List<String> parents = file.getParentFolderList();

        URL urlc = new URL(String.format(
                "https://docs.google.com/feeds/default/private/full/folder%%3A%s/contents/-/folder",
                parentDocId));
        Query qryc = new Query(urlc);
        DocumentListFeed feedc = docService.query(qryc, DocumentListFeed.class);

        for (DocumentListEntry subfolder : feedc.getEntries()) {
            // loops trough all the subfolders
            if (subfolder.getTitle().getPlainText().equals(parents.get(1))) {
                // TODO
            }
        }

        return null;

    }

    private DocumentListEntry createFolder(String folderName) throws IOException, ServiceException {
        DocumentListEntry newEntry = new FolderEntry();
        newEntry.setTitle(new PlainTextConstruct(folderName));
        URL feedUrl = new URL("https://docs.google.com/feeds/default/private/full/");
        return docService.insert(feedUrl, newEntry);
    }

    private DocumentListEntry moveToFolder(DocumentListEntry sourceEntry, DocumentListEntry destFolderEntry)
            throws IOException, MalformedURLException, ServiceException {

        DocumentListEntry newEntry = null;

        String docType = sourceEntry.getType();
        if (docType.equals(DocumentType.DOCUMENT.toString())) {
            newEntry = new DocumentEntry();
        }
        else if (docType.equals(DocumentType.PRESENTATION.toString())) {
            newEntry = new PresentationEntry();
        }
        else if (docType.equals(DocumentType.SPREADSHEET.toString())) {
            newEntry = new SpreadsheetEntry();
        }
        else if (docType.equals(DocumentType.FOLDER.toString())) {
            newEntry = new FolderEntry();
        }
        else if (docType.equals(DocumentType.PDF.toString())) {
            newEntry = new PdfEntry();
        }
        else if (docType.equals(DocumentType.DRAWING.toString())) {
            newEntry = new DocumentListEntry(); // TODO
        }
        else {
            logger.trace("Source entry has an unknow type: " + docType);
            newEntry = new DocumentListEntry(); // Unknown type
        }
        newEntry.setId(sourceEntry.getId());

        String destFolderUri = ((MediaContent) destFolderEntry.getContent()).getUri();

        return docService.insert(new URL(destFolderUri), newEntry);
    }
}
